import * as grpc from '@grpc/grpc-js'
import * as pb from '../proto/hello_pb'
import {HelloClient} from '../proto/hello_grpc_pb'

const sleep = (n: number) => new Promise((r) => setTimeout(r, n))

/**
 * 客户端发起请求,等待并输出服务端返回的数据
 * @param c 客户端的grpc handle
 */
const testEcho = async (c: HelloClient) => {
    // 准备需要发送给服务端的数据
    const req = new pb.EchoRequest()
    req.setMessage('test')

    // 向服务端发送信息,使用回调函数处理服务端返回的数据
    c.echo(req, (err, data) => {
        if (err) {
            // 如果报错
            console.log('err: ', err)
        } else {
            // 这里因为ts默认严格(strict)模式,需要使用?进行非空判定
            console.log(data?.toObject())
        }
    })
}

/**
 * 客户端发起单个消息请求,服务端返回数据流
 * @param c 客户端的grpc handle
 */
const testServerStream = async (c: HelloClient) => {
    // 准备需要发送给服务端的数据
    const req = new pb.EchoRequest()
    req.setMessage('test2:')

    // 给服务端发送消息
    const st = c.serverStream(req)
    // 持续接收服务端的数据
    st.on('data', (d) => {
        console.log(d.toObject())
    })

    // 服务端发送完毕
    st.on('end', () => {
        console.log('done')
    })

    st.on('error', (err) => {
        console.log('error', err)
    })
}

/**
 * 客户端发起数据流给服务端,服务端接收了所有数据流后返回1个信息
 * @param c 客户端的grpc handle
 */
const testClientStream = async (c: HelloClient) => {
    // 定义客户端写入流
    const call = c.clientStream((err, resp) => {
        /* 接收到服务端传输来的消息 */
        if (err) {
            console.log(err)
        } else {
            // 输出返回的值
            console.log(resp?.toObject())
        }
    })

    // 进行流式数据写入到服务端
    for (let i = 0; i < 5; i++) {
        // 准备传输的消息
        const req = new pb.EchoRequest()
        req.setMessage(`test ${i}`)
        // 写入
        call.write(req)
    }

    // 写入完毕
    call.end()
}

/**
 * 双向数据流传输
 * @param c 客户端的grpc handle
 */
const testDuplexStream = async (c: HelloClient) => {
    // 初始化双端流
    const call = c.duplexStream()
    // 接收到服务端的数据
    call.on('data', (data) => {
        console.log(data.toObject())
    })

    // 收到服务端的结束消息
    call.on('end', () => {
        console.log('end')
    })

    // 循环发送数据
    for (let i = 0; i < 5; i++) {
        // 初始化发送消息
        const req = new pb.EchoRequest()
        req.setMessage(`test ${i}`)
        // 写入消息
        call.write(req)
        await sleep(500)
    }

    // 发送完毕
    call.end()
}

const main = async () => {
    // 初始化客户端handle
    const c = new HelloClient('localhost:8080', grpc.credentials.createInsecure())

    // await testEcho(c)
    // await testServerStream(c)
    // await testClientStream(c)
    await testDuplexStream(c)
}

main()
